//-
// ==========================================================================
// Copyright (C) 2005 ATI Technologies Inc. All rights reserved.
//
// Copyright (C) 1995 - 2006 Autodesk, Inc. and/or its licensors.  All 
// rights reserved.
//
// The coded instructions, statements, computer programs, and/or related 
// material (collectively the "Data") in these files contain unpublished 
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its 
// licensors, which is protected by U.S. and Canadian federal copyright 
// law and by international treaties.
//
// The Data is provided for use exclusively by You. You have the right 
// to use, modify, and incorporate this Data into other products for 
// purposes authorized by the Autodesk software license agreement, 
// without fee.
//
// The copyright notices in the Software and this entire statement, 
// including the above license grant, this restriction and the 
// following disclaimer, must be included in all copies of the 
// Software, in whole or in part, and all derivative works of 
// the Software, unless such copies or derivative works are solely 
// in the form of machine-executable object code generated by a 
// source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. 
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED 
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
// PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR 
// TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS 
// BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 
// DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK 
// AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY 
// OR PROBABILITY OF SUCH DAMAGES.
//
// ==========================================================================
//+

#ifndef GLSL_SHADER_NODE_H
#define GLSL_SHADER_NODE_H

#include <vector>

#include <maya/MFnNumericAttribute.h>
#include <maya/MNodeMessage.h>
#include <maya/MObjectArray.h>
#include <maya/MPxHwShaderNode.h>
#include <maya/MDGModifier.h>
#include <maya/MPxNode.h>
#include <maya/MStringArray.h>
#include <maya/MTypeId.h> 

#include <IAshliFX.h>

#include "Shader.h"
#include "DefaultShader.h"
#include "glslFXShader.h"

// A wee cache to minimise our gl state changes
//
class glStateCache
{
public:
	inline glStateCache() { reset(); }
	inline void reset() { bits = 0; textureUnit = -1; }
	inline void enablePosition() { if( !(bits & (1 << kPosition))) { glEnableClientState(GL_VERTEX_ARRAY); bits |= (1 << kPosition); } }
	inline void disablePosition() { if( bits & (1 << kPosition)) { glDisableClientState(GL_VERTEX_ARRAY); bits &= ~(1 << kPosition); } }
	inline void enableNormal() { if( !(bits & (1 << kNormal))) { glEnableClientState(GL_NORMAL_ARRAY); bits |= (1 << kNormal); } }
	inline void disableNormal() { if( bits & (1 << kNormal)) { glDisableClientState(GL_NORMAL_ARRAY); bits &= ~(1 << kNormal); } }
	inline void enableColor() { if( !(bits & (1 << kColor0))) { glEnableClientState(GL_COLOR_ARRAY); bits |= (1 << kColor0); } }
	inline void disableColor() { if( bits & (1 << kColor0)) { glDisableClientState(GL_COLOR_ARRAY); bits &= ~(1 << kColor0); } }
	inline void activeTexture( int i) { if( i != textureUnit) { textureUnit = i; glClientActiveTexture( GL_TEXTURE0 + i); } }
	inline void enableAndActivateTexCoord( int i) { activeTexture( i); if( !(bits & (1 << (kTexCoord0 + i)))) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); bits |= (1 << (kTexCoord0 + i)); } }
	inline void disableTexCoord( int i) { if( bits & (1 << (kTexCoord0 + i))) { activeTexture( i); glDisableClientState(GL_TEXTURE_COORD_ARRAY); bits &= ~(1 << (kTexCoord0 + i)); } }

private:

	enum
	{
		kPosition,
		kNormal,
		kColor0,
		kColor1,
		kTexCoord0
	};
	int		bits;
	int		textureUnit;
};
 

// Certain interfaces only exist in 7.0 and beyond
//
#if MAYA_API_VERSION >= 700
	#define _HARDWARE_RENDERER_AVAILABLE_
	#define _MULTIPLE_COLOR_SET_SUPPORT_
	class MImage;
	class MGeometryData;
#endif

class glslShaderNode : public MPxHwShaderNode
{
  public:

    glslShaderNode();
    virtual ~glslShaderNode();

    virtual void postConstructor();

    //compute when DAG change occurs (likely nothing for HwShader)
    virtual MStatus compute( const MPlug& plug, MDataBlock& data );

    //factory for node creation
    static void* creator();

    // initialization
    static MStatus initialize();

    // Drawing commands like the HW renderer needs
    virtual MStatus glBind(const MDagPath& shapePath);
    virtual MStatus glUnbind(const MDagPath& shapePath);
    virtual MStatus	glGeometry( const MDagPath& shapePath, int prim, unsigned int writable, int indexCount,
        const unsigned int * indexArray, int vertexCount, const int * vertexIDs, const float * vertexArray,
        int normalCount, const float ** normalArrays, int colorCount, const float ** colorArrays, int texCoordCount,
        const float ** texCoordArrays);

	// Method to override to let Maya know this shader is batchable. 
	virtual bool	supportsBatching() const;

#ifdef _HARDWARE_RENDERER_AVAILABLE_
	// Overridden to draw an image for swatch rendering.
	///
	virtual MStatus renderSwatchImage( MImage & image );
#endif

    //
    //attribute connection handling functions
    //
	virtual MStatus	connectionMade( const MPlug& plug, const MPlug& otherPlug, bool asSrc );
	virtual MStatus	connectionBroken( const MPlug& plug, const MPlug& otherPlug, bool asSrc );

	virtual bool getInternalValueInContext( const MPlug&,
											  MDataHandle&,
											  MDGContext&);
    virtual bool setInternalValueInContext( const MPlug&,
											  const MDataHandle&,
											  MDGContext&);
	
    virtual void copyInternalData ( MPxNode * ); 
 
    //
    //attribute request interface
    //
    virtual unsigned int dirtyMask() { return kDirtyAll;};
    virtual int normalsPerVertex();
    virtual int colorsPerVertex();
    virtual int texCoordsPerVertex();
	// See the dependent function parseUseAttributeList(). concerning
	// how this data is filled in.
#ifdef _MULTIPLE_COLOR_SET_SUPPORT_
    virtual int getColorSetNames( MStringArray &names);
#endif
    virtual int getTexCoordSetNames( MStringArray &names);

    //query functions
    bool printVertexShader( int pass);
    bool printPixelShader( int pass);

    static glslShaderNode* findNodeByName(const MString &name);

    //
    //static variables
    //

    //shader Type ID to allow it to live in files
    static  MTypeId sId;
    
    //attributes for selecting shaders
	static  MObject	sShader;
	static  MObject	sTechnique;
	static  MObject	sTechniqueList;
	static  MObject sShaderPath;

    //attributes for naked textures
    static MObject sNakedTexCoords[8];

#ifdef _MULTIPLE_COLOR_SET_SUPPORT_
    //attributes for naked colors
    static MObject sNakedColors[2];
#endif

    static const char *nakedSetNames[8];

    //call back to configure shaders, post load
    static void rejigShaders( void *data);

  private:


    enum CubeFace { cfLeft, cfRight, cfTop, cfBottom, cfFront, cfBack};

	// Enum to delineate Maya vertex attribute data 
	enum MayaType {
		kNonMaya,
        kNormal,
		kTangent,
		kBinormal,
		kUvSet,
		kColorSet
	};
    MString m_nakedTexSets[8];
    int m_setNums[8]; // These are the actual Maya set numbers
	int m_maxSetNum; // The highest actual set we are using
	MayaType m_mayaType[8];

	glStateCache m_glState;

#ifdef _MULTIPLE_COLOR_SET_SUPPORT_
    MString m_nakedColorSets[2];
    int m_colorSetNums[2]; // These are the actual Maya set numbers
	MayaType m_colorMayaType[2];
#endif

    //find a fileTexture2D node from a plug
    MObject findFileTextureNode( const MPlug &plug);

    //find an envCube node from a plug
    MObject findEnvCubeNode( const MPlug &plug);

    void loadCubeFace( CubeFace cf, MObject &cube, MFnDependencyNode &dn);

    void updateBoundAttributes( const MDagPath& shapePath);
    void configureUniformAttrib( MString &name, int pNum, shader::DataType type, shader::Semantic sm, float* defVal,
                                            MFnDependencyNode &dn, MDGModifier &mod);

    //
    // data value updates
    //
    //   Thes routines are called at bind time to propagate attribute
    // state to the shader. It is done at bind time, because all updates
    // arrive piecemeal.
    void BindSamplerData();
    void BindUniformData();

    MString m_shaderName;
    MString m_shaderPath;
    MString m_techniqueName;
    MString m_techniqueList;
    int m_technique; //only figure this out when the technique or shader changes
    shader *m_shader;
    bool m_shaderDirty;

	// The number of passes to render in between bind/unbind. 0 means we're using
	// the default shader
	int m_passCount;

    static shader *sDefShader;

    //
    // these handle uniform parameters exposed to the user
    //  They can be connected to the scene via plugs
    struct uniformAttrib {
      MString name;
      MObject attrib;
      MObject attrib2; //for vec4s
      shader::DataType type; //to track for type matching
      int pNum; //parameter number
      bool dirty;
    };

    std::vector<uniformAttrib> m_uniformAttribList;

    //
    // These handle textures
    //  They can be connected to the scene with a plug
    //  A plug to a texture node allows it to connect to an image
    struct samplerAttrib {
      MString name;
      MObject attrib;
      MObject minFilterAttrib;
      MObject magFilterAttrib;
      MObject wrapAttrib;
      MObject anisoAttrib;
      int pNum;
      GLuint texName;
      GLenum minFilter;
      GLenum magFilter;
      GLenum wrapMode;
      float maxAniso;
      bool dirty;
    };

    std::vector<samplerAttrib> m_samplerAttribList;

    //
    // These handle texture coords
    //  They need to be connected to the scene
    struct attributeAttrib {
      MString name;
      MString setName;
      MObject attrib;
      int handle; //which generic attribite to use
      int set;    //which set id to use from Maya 
	  MayaType mtype; // set type from Maya
      int pNum;
    };

    std::vector<attributeAttrib> m_attributeAttribList;

	// Local variables to keep track information of attrib information
	// that is required from multiple entry points in Maya. 
	//
	bool m_parsedUserAttribList;
	int	m_numUVsets;
	MStringArray m_uvSetNames;
	int m_numColorSets;
	MStringArray m_colorSetNames;
	int m_numNormals;

	void parseUserAttributeList();

    //
    // These handle uniform parameters hidden from the user
    struct boundUniform {
      MString name;
      int pNum;
      shader::Semantic usage;
    };

    std::vector<boundUniform> m_boundUniformList;

    bool rebuildShader();

    //create / delete attributes based on active shader
    void configureAttribs();

    void configureTexCoords( int normalCount, const float ** normalArrays, int texCoordCount,
                                        const float ** texCoordArrays,
										int colorCount, const float **colorArrays );

    bool locateFile( const MString &name, MString &path);

    //this list allows us to access all nodes on callbacks
    // would it be better to just query from Maya?
    static std::vector<glslShaderNode*> sNodeList;


};


#endif //GLSL_SHADER_NODE_H

